import tkinter as tk
from tkinter import ttk, messagebox
import requests
import threading
import time
from typing import Dict, List, Any

from src.api.api_server import start_server, stop_server, is_server_running
from src.core.config import config

class WMSSimpleUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("🏭 WMS Sample - 料位管理系统")
        self.root.geometry("1200x800")
        self.root.configure(bg='#F8F9FA')  # 浅灰背景
        
        # 设置窗口图标和样式
        try:
            self.root.state('zoomed')  # Windows最大化
        except:
            pass
        
        # 状态变量
        self.server_running = False
        self.api_base_url = f"http://{config.api_host}:{config.api_port}"
        
        # 创建界面
        self.create_widgets()
        
        # 启动状态检查线程
        self.start_status_check()
        
        # 注释掉自动启动API服务器 - 开发环境手动控制
        # self.auto_start_server()
    
    def create_widgets(self):
        """创建界面组件"""
        # 主框架
        main_frame = tk.Frame(self.root, bg='#F8F9FA', padx=15, pady=15)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        title_label = tk.Label(main_frame, text="🏭 WMS Sample 料位管理系统", 
                              font=('Microsoft YaHei', 20, 'bold'),
                              bg='#F8F9FA', fg='#2C3E50')
        title_label.pack(pady=(0, 25))
        
        # 服务控制面板
        self.create_server_control_panel(main_frame)
        
        # 选项卡
        self.create_notebook(main_frame)
    
    def create_server_control_panel(self, parent):
        """创建服务控制面板"""
        control_frame = tk.LabelFrame(parent, text="⚙️ 服务控制", 
                                     font=('Microsoft YaHei', 12, 'bold'),
                                     bg='#F8F9FA', fg='#2C3E50',
                                     relief="flat", bd=1)
        control_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        control_content = tk.Frame(control_frame, bg='#F8F9FA')
        control_content.pack(fill=tk.X, padx=10, pady=10)
        
        # 状态显示
        status_frame = tk.Frame(control_content, bg='#F8F9FA')
        status_frame.pack(fill=tk.X, pady=(0, 15))
        
        tk.Label(status_frame, text="🔧 服务状态:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 8))
        self.status_label = tk.Label(status_frame, text="●停止", foreground="red",
                                    font=('Microsoft YaHei', 10, 'bold'),
                                    bg='#F8F9FA')
        self.status_label.pack(side=tk.LEFT, padx=(0, 25))
        
        tk.Label(status_frame, text="🔌 端口:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 8))
        self.port_var = tk.StringVar(value=str(config.api_port))
        port_entry = tk.Entry(status_frame, textvariable=self.port_var, width=8,
                             font=('Microsoft YaHei', 10), relief="flat", bd=1)
        port_entry.pack(side=tk.LEFT, padx=(0, 25))
        
        tk.Label(status_frame, text="🌐 API地址:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 8))
        self.url_label = tk.Label(status_frame, text=self.api_base_url, foreground="blue",
                                 font=('Microsoft YaHei', 10),
                                 bg='#F8F9FA', cursor="hand2")
        self.url_label.pack(side=tk.LEFT)
        
        # 控制按钮
        button_frame = tk.Frame(control_content, bg='#F8F9FA')
        button_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 15,
            'pady': 8
        }
        
        self.start_btn = tk.Button(button_frame, text="▶️ 启动服务", 
                                  bg="#27AE60", fg="white",
                                  activebackground="#2ECC71",
                                  command=self.start_server, **btn_style)
        self.start_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        self.stop_btn = tk.Button(button_frame, text="⏹️ 停止服务", 
                                 bg="#E74C3C", fg="white",
                                 activebackground="#C0392B",
                                 command=self.stop_server, state="disabled", **btn_style)
        self.stop_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        refresh_status_btn = tk.Button(button_frame, text="🔄 刷新状态", 
                                      bg="#3498DB", fg="white",
                                      activebackground="#2980B9",
                                      command=self.refresh_status, **btn_style)
        refresh_status_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        api_docs_btn = tk.Button(button_frame, text="📚 API文档", 
                                bg="#9B59B6", fg="white",
                                activebackground="#8E44AD",
                                command=self.open_api_docs, **btn_style)
        api_docs_btn.pack(side=tk.LEFT)
    
    def create_notebook(self, parent):
        """创建选项卡"""
        self.notebook = ttk.Notebook(parent)
        self.notebook.pack(fill=tk.BOTH, expand=True)
        
        # 料盘管理选项卡
        self.create_plate_tab()
        
        # 样品管理选项卡
        self.create_sample_tab()
        
        # 查询功能选项卡
        self.create_query_tab()
    
    def create_plate_tab(self):
        """创建料盘管理选项卡"""
        plate_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(plate_frame, text="📋 料盘管理")
        
        # 料盘列表
        list_frame = tk.LabelFrame(plate_frame, text="📋 料盘列表", 
                                  font=('Microsoft YaHei', 12, 'bold'),
                                  bg='#F8F9FA', fg='#2C3E50',
                                  relief="flat", bd=1)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 15), padx=5)
        
        # 内容框架
        list_content = tk.Frame(list_frame, bg='#F8F9FA')
        list_content.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建Treeview
        columns = ("名称", "容量", "已占用", "可用", "禁用", "描述")
        self.plate_tree = ttk.Treeview(list_content, columns=columns, show="headings", height=8)
        
        for col in columns:
            self.plate_tree.heading(col, text=col)
            self.plate_tree.column(col, width=100)
        
        # 滚动条
        plate_scrollbar = ttk.Scrollbar(list_content, orient="vertical", command=self.plate_tree.yview)
        self.plate_tree.configure(yscrollcommand=plate_scrollbar.set)
        
        self.plate_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        plate_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 操作按钮
        plate_btn_frame = tk.Frame(plate_frame, bg='#F8F9FA')
        plate_btn_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 15,
            'pady': 8
        }
        
        refresh_btn = tk.Button(plate_btn_frame, text="🔄 刷新列表", 
                               bg="#3498DB", fg="white",
                               activebackground="#2980B9",
                               command=self.refresh_plates, **btn_style)
        refresh_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        create_btn = tk.Button(plate_btn_frame, text="➕ 创建料盘", 
                              bg="#27AE60", fg="white",
                              activebackground="#2ECC71",
                              command=self.create_plate, **btn_style)
        create_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        edit_btn = tk.Button(plate_btn_frame, text="✏️ 修改料盘", 
                            bg="#F39C12", fg="white",
                            activebackground="#E67E22",
                            command=self.edit_plate, **btn_style)
        edit_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        delete_btn = tk.Button(plate_btn_frame, text="🗑️ 删除料盘", 
                              bg="#E74C3C", fg="white",
                              activebackground="#C0392B",
                              command=self.delete_plate, **btn_style)
        delete_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        view_btn = tk.Button(plate_btn_frame, text="👁️ 查看料位", 
                            bg="#9B59B6", fg="white",
                            activebackground="#8E44AD",
                            command=self.view_positions, **btn_style)
        view_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        clear_btn = tk.Button(plate_btn_frame, text="🧹 批量清空", 
                             bg="#FF6B6B", fg="white",
                             activebackground="#FF5252",
                             command=self.clear_plate_positions, **btn_style)
        clear_btn.pack(side=tk.LEFT)
    
    def create_sample_tab(self):
        """创建样品管理选项卡"""
        sample_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(sample_frame, text="📦 样品管理")
        
        # 创建左右分栏布局
        main_paned = tk.PanedWindow(sample_frame, orient=tk.HORIZONTAL, bg='#F8F9FA',
                                   sashwidth=8, sashrelief="flat")
        main_paned.pack(fill=tk.BOTH, expand=True)
        
        # 左侧操作区
        left_frame = tk.Frame(main_paned, bg='#F8F9FA', width=400)
        main_paned.add(left_frame, minsize=350)
        
        # 右侧料位展示区
        right_frame = tk.Frame(main_paned, bg='#F8F9FA')
        main_paned.add(right_frame, minsize=500)
        
        # 创建左侧操作区内容
        self.create_sample_operations(left_frame)
        
        # 创建右侧料位展示区内容
        self.create_sample_position_view(right_frame)
    
    def create_sample_operations(self, parent):
        """创建样品操作区"""
        # 样品放置区
        place_frame = tk.LabelFrame(parent, text="📥 样品放置", 
                                   font=('Microsoft YaHei', 12, 'bold'),
                                   bg='#F8F9FA', fg='#2C3E50',
                                   relief="flat", bd=1)
        place_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        place_content = tk.Frame(place_frame, bg='#F8F9FA')
        place_content.pack(fill=tk.X, padx=10, pady=10)
        
        # 样品ID输入
        row1 = tk.Frame(place_content, bg='#F8F9FA')
        row1.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(row1, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.sample_id_var = tk.StringVar()
        sample_entry = tk.Entry(row1, textvariable=self.sample_id_var, width=30,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        sample_entry.pack(fill=tk.X, pady=(5, 0))
        
        # 料盘选择
        row2 = tk.Frame(place_content, bg='#F8F9FA')
        row2.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(row2, text="📋 料盘:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.plate_combo_var = tk.StringVar()
        self.plate_combo = ttk.Combobox(row2, textvariable=self.plate_combo_var, width=28,
                                       font=('Microsoft YaHei', 10))
        self.plate_combo.pack(fill=tk.X, pady=(5, 0))
        # 绑定料盘选择事件
        self.plate_combo.bind('<<ComboboxSelected>>', self.on_plate_selected)
        
        # 料位输入
        row3 = tk.Frame(place_content, bg='#F8F9FA')
        row3.pack(fill=tk.X, pady=(0, 15))
        
        tk.Label(row3, text="📍 料位:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.position_var = tk.StringVar()
        position_entry = tk.Entry(row3, textvariable=self.position_var, width=30,
                                 font=('Microsoft YaHei', 10), relief="flat", bd=1)
        position_entry.pack(fill=tk.X, pady=(5, 0))
        
        # 操作按钮
        btn_frame = tk.Frame(place_content, bg='#F8F9FA')
        btn_frame.pack(fill=tk.X)
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 9, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 12,
            'pady': 6
        }
        
        place_btn = tk.Button(btn_frame, text="📥 放置样品", 
                             bg="#27AE60", fg="white",
                             activebackground="#2ECC71",
                             command=self.place_sample, **btn_style)
        place_btn.pack(side=tk.LEFT, padx=(0, 8))
        
        get_pos_btn = tk.Button(btn_frame, text="🔍 获取可用", 
                               bg="#3498DB", fg="white",
                               activebackground="#2980B9",
                               command=self.get_available_position, **btn_style)
        get_pos_btn.pack(side=tk.LEFT)
        
        # 样品移除区
        remove_frame = tk.LabelFrame(parent, text="🗑️ 样品移除", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1)
        remove_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        remove_content = tk.Frame(remove_frame, bg='#F8F9FA')
        remove_content.pack(fill=tk.X, padx=10, pady=10)
        
        tk.Label(remove_content, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(anchor=tk.W)
        self.remove_sample_var = tk.StringVar()
        remove_entry = tk.Entry(remove_content, textvariable=self.remove_sample_var, width=30,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        remove_entry.pack(fill=tk.X, pady=(5, 10))
        
        remove_btn = tk.Button(remove_content, text="🗑️ 移除样品", 
                              bg="#E74C3C", fg="white",
                              activebackground="#C0392B",
                              command=self.remove_sample, **btn_style)
        remove_btn.pack(anchor=tk.W)
        
        # 快捷操作区
        quick_frame = tk.LabelFrame(parent, text="⚡ 快捷操作", 
                                   font=('Microsoft YaHei', 12, 'bold'),
                                   bg='#F8F9FA', fg='#2C3E50',
                                   relief="flat", bd=1)
        quick_frame.pack(fill=tk.X, padx=5)
        
        quick_content = tk.Frame(quick_frame, bg='#F8F9FA')
        quick_content.pack(fill=tk.X, padx=10, pady=10)
        
        refresh_plates_btn = tk.Button(quick_content, text="🔄 刷新料盘", 
                                      bg="#9B59B6", fg="white",
                                      activebackground="#8E44AD",
                                      command=self.refresh_plates, **btn_style)
        refresh_plates_btn.pack(fill=tk.X, pady=(0, 5))
        
        clear_inputs_btn = tk.Button(quick_content, text="🧹 清空输入", 
                                    bg="#95A5A6", fg="white",
                                    activebackground="#7F8C8D",
                                    command=self.clear_sample_inputs, **btn_style)
        clear_inputs_btn.pack(fill=tk.X)
    
    def create_sample_position_view(self, parent):
        """创建料位展示区"""
        # 标题区
        header_frame = tk.Frame(parent, bg='#F8F9FA')
        header_frame.pack(fill=tk.X, pady=(0, 15))
        
        title_label = tk.Label(header_frame, text="🔲 料位布局", 
                              font=('Microsoft YaHei', 16, 'bold'),
                              bg='#F8F9FA', fg='#2C3E50')
        title_label.pack(side=tk.LEFT)
        
        # 统计信息区
        self.stats_frame = tk.Frame(header_frame, bg='#F8F9FA')
        self.stats_frame.pack(side=tk.RIGHT)
        
        # 料位展示区
        position_frame = tk.LabelFrame(parent, text="", 
                                      bg='#F8F9FA', fg='#2C3E50',
                                      relief="flat", bd=1)
        position_frame.pack(fill=tk.BOTH, expand=True, padx=5)
        
        # 滚动区域
        canvas_frame = tk.Frame(position_frame, bg='#F8F9FA')
        canvas_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        self.position_canvas = tk.Canvas(canvas_frame, bg='#FFFFFF', relief="flat", bd=1)
        v_scrollbar = ttk.Scrollbar(canvas_frame, orient="vertical", command=self.position_canvas.yview)
        h_scrollbar = ttk.Scrollbar(canvas_frame, orient="horizontal", command=self.position_canvas.xview)
        
        self.position_canvas.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set)
        
        self.position_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        v_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        h_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 创建可滚动框架
        self.position_container = tk.Frame(self.position_canvas, bg='#FFFFFF')
        self.canvas_window = self.position_canvas.create_window((0, 0), window=self.position_container, anchor="nw")
        
        # 绑定滚动事件
        self.position_container.bind('<Configure>', self.on_position_frame_configure)
        self.position_canvas.bind('<Configure>', self.on_position_canvas_configure)
        
        # 初始化变量
        self.current_plate_positions = []
        self.position_buttons = {}
        self.stat_cards = {}
        
        # 显示提示信息
        self.show_position_placeholder()
    
    def show_position_placeholder(self):
        """显示料位区域占位提示"""
        placeholder = tk.Label(self.position_container, 
                              text="💡 请选择料盘查看料位布局",
                              font=('Microsoft YaHei', 14),
                              bg='#FFFFFF', fg='#7F8C8D',
                              pady=50)
        placeholder.pack(expand=True)
    
    def on_plate_selected(self, event=None):
        """料盘选择事件处理"""
        plate_name = self.plate_combo_var.get().strip()
        if plate_name:
            self.load_plate_positions(plate_name)
    
    def load_plate_positions(self, plate_name):
        """加载料盘料位信息"""
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/positions")
            self.current_plate_positions = result['positions']
            self.update_position_display()
        except Exception as e:
            # 清空显示
            self.clear_position_display()
            print(f"加载料位信息失败: {str(e)}")
    
    def update_position_display(self):
        """更新料位显示"""
        # 清空现有内容
        for widget in self.position_container.winfo_children():
            widget.destroy()
        
        self.position_buttons.clear()
        
        if not self.current_plate_positions:
            self.show_position_placeholder()
            return
        
        # 更新统计信息
        self.update_stats_display()
        
        # 计算网格布局
        import math
        total_positions = len(self.current_plate_positions)
        cols = min(8, math.ceil(math.sqrt(total_positions)))  # 最多8列
        rows = math.ceil(total_positions / cols)
        
        # 创建料位按钮
        for i, pos in enumerate(self.current_plate_positions):
            row = i // cols
            col = i % cols
            
            btn = self.create_position_button_sample(self.position_container, pos)
            btn.grid(row=row, column=col, padx=3, pady=3, sticky="nsew")
            
            self.position_buttons[pos["position_index"]] = btn
        
        # 配置网格权重
        for i in range(rows):
            self.position_container.grid_rowconfigure(i, weight=1)
        for i in range(cols):
            self.position_container.grid_columnconfigure(i, weight=1)
        
        # 更新滚动区域
        self.position_container.update_idletasks()
        self.position_canvas.configure(scrollregion=self.position_canvas.bbox("all"))
    
    def create_position_button_sample(self, parent, position):
        """创建样品管理用的料位按钮"""
        pos_index = position["position_index"]
        status = position["status"]
        sample_id = position["sample_id"]
        
        # 现代化配色
        colors = {
            "available": {"bg": "#27AE60", "fg": "white", "active_bg": "#2ECC71"},
            "occupied": {"bg": "#E74C3C", "fg": "white", "active_bg": "#C0392B"},
            "disabled": {"bg": "#95A5A6", "fg": "white", "active_bg": "#7F8C8D"}
        }
        
        color = colors.get(status, {"bg": "white", "fg": "black", "active_bg": "lightgray"})
        
        # 按钮文本
        if status == "occupied" and sample_id:
            text = f"{pos_index}\n{sample_id[:6]}"  # 显示前6个字符
        else:
            text = str(pos_index)
        
        # 创建按钮
        btn = tk.Button(
            parent,
            text=text,
            width=6,
            height=3,
            bg=color["bg"],
            fg=color["fg"],
            activebackground=color["active_bg"],
            activeforeground="white",
            font=('Microsoft YaHei', 8, 'bold'),
            relief="flat",
            borderwidth=0,
            cursor="hand2",
            command=lambda p=pos_index: self.on_sample_position_click(p)
        )
        
        return btn
    
    def on_sample_position_click(self, position_index):
        """样品管理中的料位点击事件"""
        # 自动填入料位号
        self.position_var.set(str(position_index))
        
        # 高亮选中的料位
        self.highlight_sample_position(position_index)
    
    def highlight_sample_position(self, pos_index):
        """高亮选中的料位"""
        # 重置所有按钮边框
        for btn in self.position_buttons.values():
            btn.config(relief="flat", borderwidth=0)
        
        # 高亮选中的按钮
        if pos_index in self.position_buttons:
            self.position_buttons[pos_index].config(relief="solid", borderwidth=2, 
                                                   highlightbackground="#3498DB",
                                                   highlightcolor="#3498DB")
    
    def update_stats_display(self):
        """更新统计信息显示"""
        # 清空现有统计卡片
        for widget in self.stats_frame.winfo_children():
            widget.destroy()
        
        if not self.current_plate_positions:
            return
        
        # 计算统计信息
        stats = {"total": len(self.current_plate_positions), "available": 0, "occupied": 0, "disabled": 0}
        for pos in self.current_plate_positions:
            stats[pos["status"]] += 1
        
        # 创建统计卡片
        self.create_stats_card(self.stats_frame, "总计", stats['total'], "#3498DB", 0)
        self.create_stats_card(self.stats_frame, "可用", stats['available'], "#27AE60", 1)
        self.create_stats_card(self.stats_frame, "占用", stats['occupied'], "#E74C3C", 2)
        self.create_stats_card(self.stats_frame, "禁用", stats['disabled'], "#95A5A6", 3)
    
    def create_stats_card(self, parent, label, value, color, column):
        """创建统计卡片"""
        card_frame = tk.Frame(parent, bg=color, relief="flat", bd=0)
        card_frame.grid(row=0, column=column, padx=3, pady=0, ipadx=8, ipady=4)
        
        value_label = tk.Label(card_frame, text=str(value), 
                              font=('Microsoft YaHei', 10, 'bold'),
                              bg=color, fg='white')
        value_label.pack()
        
        label_label = tk.Label(card_frame, text=label, 
                              font=('Microsoft YaHei', 7),
                              bg=color, fg='white')
        label_label.pack()
    
    def clear_position_display(self):
        """清空料位显示"""
        for widget in self.position_container.winfo_children():
            widget.destroy()
        self.position_buttons.clear()
        self.current_plate_positions = []
        
        # 清空统计信息
        for widget in self.stats_frame.winfo_children():
            widget.destroy()
        
        self.show_position_placeholder()
    
    def clear_sample_inputs(self):
        """清空样品输入框"""
        self.sample_id_var.set("")
        self.position_var.set("")
        self.remove_sample_var.set("")
        
        # 重置料位高亮
        for btn in self.position_buttons.values():
            btn.config(relief="flat", borderwidth=0)
    
    def create_query_tab(self):
        """创建查询功能选项卡"""
        query_frame = tk.Frame(self.notebook, bg='#F8F9FA', padx=15, pady=15)
        self.notebook.add(query_frame, text="🔍 查询功能")
        
        # 样品位置查询
        search_frame = tk.LabelFrame(query_frame, text="🔍 样品位置查询", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1)
        search_frame.pack(fill=tk.X, pady=(0, 15), padx=5)
        
        # 内容框架
        search_content = tk.Frame(search_frame, bg='#F8F9FA')
        search_content.pack(fill=tk.X, padx=10, pady=10)
        
        search_row = tk.Frame(search_content, bg='#F8F9FA')
        search_row.pack(fill=tk.X)
        
        tk.Label(search_row, text="🏷️ 样品ID:", font=('Microsoft YaHei', 10),
                bg='#F8F9FA', fg='#2C3E50').pack(side=tk.LEFT, padx=(0, 8))
        self.search_sample_var = tk.StringVar()
        search_entry = tk.Entry(search_row, textvariable=self.search_sample_var, width=20,
                               font=('Microsoft YaHei', 10), relief="flat", bd=1)
        search_entry.pack(side=tk.LEFT, padx=(0, 15))
        
        # 现代化按钮样式
        btn_style = {
            'font': ('Microsoft YaHei', 10, 'bold'),
            'relief': 'flat',
            'bd': 0,
            'cursor': 'hand2',
            'padx': 15,
            'pady': 8
        }
        
        search_btn = tk.Button(search_row, text="🔍 查询位置", 
                              bg="#3498DB", fg="white",
                              activebackground="#2980B9",
                              command=self.search_sample, **btn_style)
        search_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        clear_btn = tk.Button(search_row, text="🧹 清空", 
                             bg="#95A5A6", fg="white",
                             activebackground="#7F8C8D",
                             command=lambda: self.search_sample_var.set(""), **btn_style)
        clear_btn.pack(side=tk.LEFT)
        
        # 查询结果显示
        result_frame = tk.LabelFrame(query_frame, text="📊 查询结果", 
                                    font=('Microsoft YaHei', 12, 'bold'),
                                    bg='#F8F9FA', fg='#2C3E50',
                                    relief="flat", bd=1)
        result_frame.pack(fill=tk.BOTH, expand=True, padx=5)
        
        # 内容框架
        result_content = tk.Frame(result_frame, bg='#F8F9FA')
        result_content.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        self.result_text = tk.Text(result_content, height=15, width=80,
                                  font=('Microsoft YaHei', 10),
                                  bg='#FFFFFF', fg='#2C3E50',
                                  relief="flat", bd=1,
                                  wrap=tk.WORD)
        result_scrollbar = ttk.Scrollbar(result_content, orient="vertical", command=self.result_text.yview)
        self.result_text.configure(yscrollcommand=result_scrollbar.set)
        
        self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        result_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    
    def on_position_frame_configure(self, event):
        """料位框架配置事件"""
        self.position_canvas.configure(scrollregion=self.position_canvas.bbox("all"))
    
    def on_position_canvas_configure(self, event):
        """料位画布配置事件"""
        canvas_width = event.width
        self.position_canvas.itemconfig(self.canvas_window, width=canvas_width)
    
    # ==================== 服务器控制方法 ====================
    
    def start_server(self):
        """启动服务器"""
        try:
            port = int(self.port_var.get())
            config.set("api_port", port)
            
            success, message = start_server(port=port)
            if success:
                self.server_running = True
                self.update_server_status()
                messagebox.showinfo("成功", message)
            else:
                messagebox.showwarning("警告", message)
        except ValueError:
            messagebox.showerror("错误", "端口必须是数字")
        except Exception as e:
            messagebox.showerror("错误", f"启动服务器失败: {str(e)}")
    
    def stop_server(self):
        """停止服务器"""
        try:
            success, message = stop_server()
            if success:
                self.server_running = False
                self.update_server_status()
                messagebox.showinfo("成功", message)
            else:
                messagebox.showwarning("警告", message)
        except Exception as e:
            messagebox.showerror("错误", f"停止服务器失败: {str(e)}")
    
    def refresh_status(self):
        """刷新服务器状态"""
        self.server_running = is_server_running()
        self.update_server_status()
    
    def update_server_status(self):
        """更新服务器状态显示"""
        if self.server_running:
            self.status_label.config(text="●运行中", foreground="green")
            self.start_btn.config(state="disabled")
            self.stop_btn.config(state="normal")
        else:
            self.status_label.config(text="●停止", foreground="red")
            self.start_btn.config(state="normal")
            self.stop_btn.config(state="disabled")
        
        # 更新API地址
        port = self.port_var.get()
        self.api_base_url = f"http://{config.api_host}:{port}"
        self.url_label.config(text=self.api_base_url)
    
    def auto_start_server(self):
        """自动启动API服务器"""
        def start_in_background():
            try:
                # 等待界面完全加载
                time.sleep(1)
                
                # 检查服务器是否已经运行
                if not is_server_running():
                    print("正在自动启动API服务器...")
                    success, message = start_server()
                    if success:
                        self.server_running = True
                        print("✅ API服务器启动成功")
                        # 更新UI状态
                        self.root.after(0, self.update_server_status)
                        # 自动刷新料盘列表
                        self.root.after(2000, self.refresh_plates)  # 2秒后刷新
                    else:
                        print(f"❌ API服务器启动失败: {message}")
                else:
                    self.server_running = True
                    print("✅ API服务器已在运行")
                    self.root.after(0, self.update_server_status)
                    self.root.after(1000, self.refresh_plates)  # 1秒后刷新
            except Exception as e:
                print(f"❌ 自动启动API服务器时发生错误: {e}")
        
        # 在后台线程中启动服务器
        start_thread = threading.Thread(target=start_in_background, daemon=True)
        start_thread.start()
    
    def start_status_check(self):
        """启动状态检查线程"""
        def check_status():
            while True:
                try:
                    self.server_running = is_server_running()
                    self.root.after(0, self.update_server_status)
                    time.sleep(3)
                except:
                    pass
        
        status_thread = threading.Thread(target=check_status, daemon=True)
        status_thread.start()
    
    def open_api_docs(self):
        """打开API文档"""
        import webbrowser
        if self.server_running:
            webbrowser.open(f"{self.api_base_url}/docs")
        else:
            messagebox.showwarning("警告", "请先启动服务器")
    
    # ==================== API调用方法 ====================
    
    def api_request(self, method: str, endpoint: str, data=None) -> Dict[str, Any]:
        """发送API请求"""
        if not self.server_running:
            raise Exception("服务器未运行")
        
        url = f"{self.api_base_url}{endpoint}"
        
        try:
            if method.upper() == "GET":
                response = requests.get(url, timeout=5)
            elif method.upper() == "POST":
                response = requests.post(url, json=data, timeout=5)
            elif method.upper() == "PUT":
                response = requests.put(url, json=data, timeout=5)
            elif method.upper() == "DELETE":
                response = requests.delete(url, timeout=5)
            else:
                raise ValueError(f"不支持的HTTP方法: {method}")
            
            if response.status_code == 200:
                return response.json()
            else:
                error_detail = response.json().get("detail", "未知错误") if response.content else "请求失败"
                raise Exception(f"API错误 ({response.status_code}): {error_detail}")
                
        except requests.exceptions.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
    
    # ==================== 料盘管理方法 ====================
    
    def refresh_plates(self):
        """刷新料盘列表"""
        try:
            plates = self.api_request("GET", "/api/plates")
            
            # 清空现有数据
            for item in self.plate_tree.get_children():
                self.plate_tree.delete(item)
            
            # 添加新数据
            for plate in plates:
                self.plate_tree.insert("", "end", values=(
                    plate["name"],
                    plate["capacity"],
                    plate["occupied_count"],
                    plate["available_count"],
                    plate["disabled_count"],
                    plate["description"]
                ))
            
            # 更新料盘下拉框
            plate_names = [plate["name"] for plate in plates]
            self.plate_combo['values'] = plate_names
            
            self.log_message("料盘列表已刷新")
            
        except Exception as e:
            error_msg = str(e)
            if "服务器未运行" in error_msg:
                # 开发环境：不自动启动，提示用户手动启动
                messagebox.showwarning("提示", "API服务器未运行，请点击'启动服务'按钮手动启动")
            else:
                messagebox.showerror("错误", f"刷新料盘列表失败: {error_msg}")
    
    def create_plate(self):
        """创建料盘"""
        dialog = PlateDialog(self.root, "创建料盘")
        if dialog.result:
            try:
                result = self.api_request("POST", "/api/plates", dialog.result)
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
            except Exception as e:
                messagebox.showerror("错误", f"创建料盘失败: {str(e)}")
    
    def edit_plate(self):
        """修改料盘"""
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要修改的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        # 获取当前料盘信息
        try:
            plates = self.api_request("GET", "/api/plates")
            current_plate = next((p for p in plates if p["name"] == plate_name), None)
            if not current_plate:
                messagebox.showerror("错误", "找不到料盘信息")
                return
            
            dialog = PlateDialog(self.root, "修改料盘", current_plate)
            if dialog.result:
                try:
                    # 尝试正常更新
                    result = self.api_request("PUT", f"/api/plates/{plate_name}", dialog.result)
                    messagebox.showinfo("成功", result["message"])
                    self.refresh_plates()
                except Exception as e:
                    error_msg = str(e)
                    # 检查是否是容量冲突错误
                    if "CAPACITY_CONFLICT:" in error_msg:
                        # 提取错误信息
                        conflict_msg = error_msg.split("CAPACITY_CONFLICT:")[1]
                        
                        # 弹出确认对话框
                        confirm_msg = f"{conflict_msg}\n\n是否要清空料盘中的所有样品并重新设置容量？\n\n警告：此操作将删除料盘中的所有样品数据！"
                        if messagebox.askyesno("容量冲突", confirm_msg, icon='warning'):
                            try:
                                # 使用重置API
                                result = self.api_request("PUT", f"/api/plates/{plate_name}/reset", dialog.result)
                                messagebox.showinfo("成功", result["message"])
                                self.refresh_plates()
                            except Exception as reset_e:
                                messagebox.showerror("错误", f"重置料盘失败: {str(reset_e)}")
                    else:
                        # 其他错误直接显示
                        messagebox.showerror("错误", f"修改料盘失败: {error_msg}")
        except Exception as e:
            messagebox.showerror("错误", f"获取料盘信息失败: {str(e)}")
    
    def delete_plate(self):
        """删除料盘"""
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要删除的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        # 确认删除
        if messagebox.askyesno("确认删除", f"确定要删除料盘 '{plate_name}' 吗？\n注意：这将删除料盘中的所有样品！"):
            try:
                result = self.api_request("DELETE", f"/api/plates/{plate_name}")
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
            except Exception as e:
                messagebox.showerror("错误", f"删除料盘失败: {str(e)}")

    def view_positions(self):
        """查看料位详情"""
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要查看的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/positions")
            # 使用增强版料盘详细视图
            from src.ui.plate_detail_dialog import PlateDetailDialog
            PlateDetailDialog(self.root, plate_name, result['positions'], self.api_request)
        except Exception as e:
            messagebox.showerror("错误", f"获取料位信息失败: {str(e)}")
    
    def clear_plate_positions(self):
        """批量清空料位"""
        selection = self.plate_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请选择要清空的料盘")
            return
        
        item = self.plate_tree.item(selection[0])
        plate_name = item['values'][0]
        
        # 确认清空
        confirm_msg = f"确定要清空料盘 '{plate_name}' 中的所有样品吗？\n\n注意：\n• 此操作将移除所有样品\n• 禁用的料位状态将保持不变\n• 此操作不可撤销！"
        if messagebox.askyesno("确认批量清空", confirm_msg, icon='warning'):
            try:
                result = self.api_request("PUT", f"/api/plates/{plate_name}/clear")
                messagebox.showinfo("成功", result["message"])
                self.refresh_plates()
                
                # 如果当前显示的是这个料盘，刷新料位显示
                current_plate = self.plate_combo_var.get().strip()
                if current_plate == plate_name:
                    self.load_plate_positions(plate_name)
                    
            except Exception as e:
                error_msg = str(e)
                if "没有样品需要清空" in error_msg:
                    messagebox.showinfo("提示", f"料盘 '{plate_name}' 中没有样品需要清空")
                else:
                    messagebox.showerror("错误", f"批量清空失败: {error_msg}")
    
    # ==================== 样品管理方法 ====================
    
    def place_sample(self):
        """放置样品"""
        sample_id = self.sample_id_var.get().strip()
        plate_name = self.plate_combo_var.get().strip()
        position_str = self.position_var.get().strip()
        
        if not all([sample_id, plate_name, position_str]):
            messagebox.showwarning("警告", "请填写完整信息")
            return
        
        try:
            position_index = int(position_str)
            data = {
                "sample_id": sample_id,
                "plate_name": plate_name,
                "position_index": position_index
            }
            
            result = self.api_request("POST", "/api/samples/place", data)
            messagebox.showinfo("成功", result["message"])
            
            # 清空输入框
            self.sample_id_var.set("")
            self.position_var.set("")
            
            # 刷新料盘列表
            self.refresh_plates()
            
            # 刷新当前料位显示
            if plate_name:
                self.load_plate_positions(plate_name)
            
        except ValueError:
            messagebox.showerror("错误", "料位必须是数字")
        except Exception as e:
            messagebox.showerror("错误", f"放置样品失败: {str(e)}")
    
    def get_available_position(self):
        """获取可用料位"""
        plate_name = self.plate_combo_var.get().strip()
        if not plate_name:
            messagebox.showwarning("警告", "请选择料盘")
            return
        
        try:
            result = self.api_request("GET", f"/api/plates/{plate_name}/first-available")
            if result["available_position"] is not None:
                self.position_var.set(str(result["available_position"]))
                messagebox.showinfo("成功", f"找到可用料位: {result['available_position']}")
            else:
                messagebox.showwarning("警告", "该料盘无可用料位")
        except Exception as e:
            messagebox.showerror("错误", f"获取可用料位失败: {str(e)}")
    
    def remove_sample(self):
        """移除样品"""
        sample_id = self.remove_sample_var.get().strip()
        if not sample_id:
            messagebox.showwarning("警告", "请输入样品ID")
            return
        
        # 需要指定料盘名称
        plate_name = self.plate_combo_var.get().strip()
        if not plate_name:
            messagebox.showwarning("警告", "请先选择料盘")
            return
        
        try:
            result = self.api_request("DELETE", f"/api/samples/{plate_name}/{sample_id}")
            messagebox.showinfo("成功", result["message"])
            self.remove_sample_var.set("")
            self.refresh_plates()
            
            # 刷新当前料位显示
            if plate_name:
                self.load_plate_positions(plate_name)
                
        except Exception as e:
            messagebox.showerror("错误", f"移除样品失败: {str(e)}")
    
    # ==================== 查询功能方法 ====================
    
    def search_sample(self):
        """查询样品位置"""
        sample_id = self.search_sample_var.get().strip()
        if not sample_id:
            messagebox.showwarning("警告", "请输入样品ID")
            return
        
        try:
            result = self.api_request("GET", f"/api/samples/{sample_id}/location")
            
            message = f"样品查询结果:\n"
            message += f"样品ID: {result['sample_id']}\n"
            message += f"料盘: {result['plate_name']}\n"
            message += f"料位: {result['position_index']}\n"
            message += f"更新时间: {result['updated_at']}\n"
            message += "-" * 50 + "\n"
            
            self.result_text.insert(tk.END, message)
            self.result_text.see(tk.END)
            
        except Exception as e:
            error_message = f"查询失败: {str(e)}\n" + "-" * 50 + "\n"
            self.result_text.insert(tk.END, error_message)
            self.result_text.see(tk.END)
    
    def log_message(self, message: str):
        """记录日志消息"""
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"
        self.result_text.insert(tk.END, log_message)
        self.result_text.see(tk.END)
    
    def run(self):
        """运行UI"""
        # 启动主循环
        self.root.mainloop()

# ==================== 对话框类 ====================

class PositionDialog:
    def __init__(self, parent, plate_name, positions):
        self.dialog = tk.Toplevel(parent)
        self.dialog.title(f"料盘 {plate_name} - 料位详情")
        self.dialog.geometry("600x400")
        self.dialog.transient(parent)
        self.dialog.grab_set()
        
        # 居中显示
        self.dialog.geometry("+%d+%d" % (parent.winfo_rootx() + 100, parent.winfo_rooty() + 100))
        
        self.create_widgets(plate_name, positions)
    
    def create_widgets(self, plate_name, positions):
        main_frame = ttk.Frame(self.dialog, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        ttk.Label(main_frame, text=f"料盘: {plate_name}", font=('Arial', 12, 'bold')).pack(pady=(0, 10))
        
        # 料位列表
        tree_frame = ttk.Frame(main_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        columns = ("料位", "样品ID", "状态", "更新时间")
        tree = ttk.Treeview(tree_frame, columns=columns, show="headings", height=15)
        
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=120)
        
        # 滚动条
        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 添加数据
        for pos in positions:
            status_text = {"available": "可用", "occupied": "占用", "disabled": "禁用"}.get(pos["status"], pos["status"])
            sample_display = pos["sample_id"] if pos["sample_id"] else "空"
            
            tree.insert("", "end", values=(
                pos["position_index"],
                sample_display,
                status_text,
                pos["updated_at"][:19] if pos["updated_at"] else ""
            ))
        
        # 关闭按钮
        ttk.Button(main_frame, text="关闭", command=self.dialog.destroy).pack()

class PlateDialog:
    def __init__(self, parent, title, initial_data=None):
        self.result = None
        
        self.dialog = tk.Toplevel(parent)
        self.dialog.title(title)
        self.dialog.geometry("400x300")
        self.dialog.transient(parent)
        self.dialog.grab_set()
        
        # 居中显示
        self.dialog.geometry("+%d+%d" % (parent.winfo_rootx() + 150, parent.winfo_rooty() + 150))
        
        self.create_widgets(initial_data)
        
        # 等待对话框关闭
        self.dialog.wait_window()
    
    def create_widgets(self, initial_data):
        main_frame = ttk.Frame(self.dialog, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 料盘名称
        ttk.Label(main_frame, text="料盘名称:").pack(anchor=tk.W, pady=(0, 5))
        self.name_var = tk.StringVar(value=initial_data["name"] if initial_data else "")
        name_entry = ttk.Entry(main_frame, textvariable=self.name_var, width=30)
        name_entry.pack(fill=tk.X, pady=(0, 15))
        
        # 如果是修改模式，禁用名称输入
        if initial_data:
            name_entry.config(state="readonly")
        
        # 容量
        ttk.Label(main_frame, text="容量:").pack(anchor=tk.W, pady=(0, 5))
        self.capacity_var = tk.StringVar(value=str(initial_data["capacity"]) if initial_data else "")
        ttk.Entry(main_frame, textvariable=self.capacity_var, width=30).pack(fill=tk.X, pady=(0, 15))
        
        # 描述
        ttk.Label(main_frame, text="描述:").pack(anchor=tk.W, pady=(0, 5))
        self.description_var = tk.StringVar(value=initial_data["description"] if initial_data else "")
        ttk.Entry(main_frame, textvariable=self.description_var, width=30).pack(fill=tk.X, pady=(0, 20))
        
        # 按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X)
        
        ttk.Button(button_frame, text="确定", command=self.ok_clicked).pack(side=tk.RIGHT, padx=(10, 0))
        ttk.Button(button_frame, text="取消", command=self.cancel_clicked).pack(side=tk.RIGHT)
    
    def ok_clicked(self):
        # 验证输入
        name = self.name_var.get().strip()
        capacity_str = self.capacity_var.get().strip()
        description = self.description_var.get().strip()
        
        if not name:
            messagebox.showerror("错误", "请输入料盘名称")
            return
        
        if not capacity_str:
            messagebox.showerror("错误", "请输入容量")
            return
        
        try:
            capacity = int(capacity_str)
            if capacity <= 0:
                messagebox.showerror("错误", "容量必须大于0")
                return
        except ValueError:
            messagebox.showerror("错误", "容量必须是数字")
            return
        
        # 设置结果
        self.result = {
            "name": name,
            "capacity": capacity,
            "description": description
        }
        
        self.dialog.destroy()
    
    def cancel_clicked(self):
        self.dialog.destroy()

class UIManager:
    """UI管理器 - 包装原有的WMSSimpleUI"""
    
    def __init__(self):
        self.ui = WMSSimpleUI()
    
    def run(self):
        """运行UI"""
        self.ui.run()


if __name__ == "__main__":
    app = WMSSimpleUI()
    app.run() 